﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


using SpiritEngine.Source.ApplicationLayer;
using SpiritEngine.Source.EngineCore.DevConsole;
using SpiritEngine.Source.Utilities;


namespace SpiritEngine.Source.EngineCore
{
    #region Globals

    #endregion


    /// <summary>
    /// This class represents the Engine Core.  This is the layer that sits atop the Application Layer of the game engine (which is represented by the EngineBase class).
    /// All of the code in the EngineCore layer is OS-Independent, meaning that it should work regardless of OS.
    /// </summary>
    public class EngineCore: SE_Base, ISE_EngineCore, ISE_Object
    {
        #region Constants/Enums

        #endregion


        #region Structs

        #endregion


        #region Static Member Variables and Methods

        #endregion


        #region Member Variables

        // ========================================================================================================================================================================================================
        // Property Variables
        // ========================================================================================================================================================================================================

        private ISE_DevConsole m_DevConsole;
        private ISE_Logger m_Logger;

        // These are private to force classes that inherit from this class to declare their own member variable for use by the corresponding properties.
        // This way, for example, we can keep track of initialization state for each step in the inheritence chain.  So if the base class is initialized, but
        // the subclass is not, then the base class's IsInitialized property would return true, but the subclass's IsInitialized property would return false.
        private int m_SEObjectFlags = 0;    // Stores object flags defined by the SEObject_Flags enum.

        #endregion


        #region Events/Delegates

        #endregion


        #region Constructors and Destructors (aka Finalizers)

        public EngineCore(ISE_EngineBase parent)
        {
            if (parent == null)
                throw new ArgumentException("EngineCore(ISE_Enginebase): The parent parameter cannot be null!");


            m_Parent = parent;
        }

        #endregion


        #region Non-Public Methods

        // This section is for methods that are declared as private, protected, protected internal, or internal.

        #endregion


        #region Public Methods

        /// <summary>
        /// Initializes this object.
        /// </summary>
        /// <param name="paramsList">A variable length parameter list.
        /// 
        /// EXPECTED PARAMETERS:
        /// None</param>
        /// <returns>True if successful or false otherwise.</returns>
        public override bool Initialize(params object[] paramsList)
        {
            base.Initialize();


#if VERIFY_PARAMS
            if (!SE_Debug.VerifyParameters(paramsList, 
                                           0, 
                                           -1, 
                                           typeof(string),
                                           new ParamInfo[] { new ParamInfo() { AllowNull = false, ParamType = typeof(string) } } ))
            {

                throw new ArgumentException("EngineCore.Initialize(object[]): Invalid params!");
            }
#endif


            // Setup engine components.
            m_DevConsole = new DevConsole.DevConsole(this);
            m_DevConsole.Initialize();

            m_Logger = new Logger(this);
            m_Logger.Initialize();



            // Set the initialized flag to indicate that this object has been initialized.
            m_SEObjectFlags = SE_Misc.Flags_SetFlags(m_SEObjectFlags, (int)SEObject_Flags.Initialized);

            return true;
        }

        #endregion


        #region Interface Methods

        // This section is for methods that are part of the interfaces that the class implements.

        #region IDisposable Methods

#if USE_IDISPOSABLE

        /// <summary>
        /// This function handles the actual "disposing" of this object.
        /// ANY classes that are inherited from this class, no matter how distantly, MUST override this method so that they can perform their own cleanup!
        /// </summary>
        /// <param name="disposing">This parameter will be true if this function is being called by the public Dispose() method, or false otherwise.</param>
        protected override void Dispose(bool disposing)
        {
            // Check if this object has already been disposed.
            if (SE_Misc.Flags_HasFlags(m_SEObjectFlags, (int)SEObject_Flags.Disposed))
                return;



            if (disposing)
            {
                /*
                * The following text is from MSDN  (http://msdn.microsoft.com/en-us/library/fs2xkftw%28VS.80%29.aspx)
                * 
                * 
                * Dispose(bool disposing) executes in two distinct scenarios:
                * 
                * If disposing equals true, the method has been called directly or indirectly by a user's code and managed and unmanaged resources can be disposed.
                * If disposing equals false, the method has been called by the runtime from inside the finalizer and only unmanaged resources can be disposed. 
                * 
                * When an object is executing its finalization code, it should not reference other objects, because finalizers do not execute in any particular order. 
                * If an executing finalizer references another object that has already been finalized, the executing finalizer will fail.
                */


                // Unregister Events


                // Clean up all managed resources.
                if (m_DevConsole != null)
                {
                    m_DevConsole.Dispose();
                }

                if (m_Logger != null)
                {
                    m_Logger.Dispose();
                }
            }

            // Clean up all unmanaged resources.



            // Call the base class's Dispose() method if it has one.
            base.Dispose(disposing);
        }

#endif

        #endregion

        #endregion


        #region Event Invocation Methods

        // This section is for methods that invoke the events of this class.  For example:
        //
        // Invoke the Changed event; called whenever list changes
        // protected virtual void OnChanged(EventArgs e) 
        // {
        //		if (Changed != null)
        //			Changed(this, e);
        // }

        #endregion


        #region Operators

        #endregion


        #region Debug Methods

        // This will compile the debug code only if the DEBUG symbol is defined.
        // To define this symbol for all source files in the project, open the Project Properties,
        // and go to the Build tab.  Check the "Define DEBUG constant" checkbox.  With this box checked,
        // the compiler will automatically define the symbol DEBUG.
#if (DEBUG)
        // put all debug methods in here...
#endif

        #endregion


        #region Properties

        /// <summary>
        /// This property provides access to the DevConsole.
        /// </summary>
        public ISE_DevConsole DevConsole
        {
            get
            {
                return m_DevConsole;
            }
        }

        /// <summary>
        /// This property provides access to the Logger.
        /// </summary>
        public ISE_Logger Logger
        {
            get
            {
                return m_Logger;
            }
        }

        /// <summary>
        /// Provides access to the object's "Spirit Engine Object" flags.
        /// </summary>
        public override int SEObjectFlags
        {
            get
            {
                return m_SEObjectFlags;
            }
            protected set // Can only be set from within this class and subclasses
            {
                m_SEObjectFlags = value;
            }
        } 

        #endregion


    }
}
